<script>
  export default {
    data() {
      return {
        selfId: 0,
        // 在线状态
        state: 1,
        goodsID:0,
        recenttext:'',
        selfListData: {},
        //搜索用户
        search: "",
        //用户列表渲染数据
        userListData: [],
        //用户点击选中变色
        act: 0,
        // 加号弹框
        dialogVisible: false,
        //模拟花间一壶酒用户的历史信息
        userInfoList2: [],
        //历史信息
        userInfoList: [],
        //输入框
        textarea: "",
        //滚动条距离顶部距离
        scrollTop: 0,
        //发送和输入显隐
        isshow: 0,
        websock: null,
        page: 1,
        page1: 1,
        urlhh: '',
        abcd: 0,
        index: -1,
        dialogInfo:{},
        firstRunFlag: true,
        other_id:0,
        category:0,
        isUpdate:true,
      };
    },
    created() {
      this.initWebSocket()
    },
    destroyed() {
      this.websock.close() //离开路由之后断开websocket连接
    },
  
    methods: {
      initWebSocket() {
        // token为访问令牌，一般登录成功，就会返回token
        const token = window.sessionStorage.getItem('token')
        // 其中线上的链接为wss://,在本地上的链接为ws://
        const wsuri = "wss://www.xxxxxxxx.com:8002/chat_ws/"
        // const wsuri = `ws://192.168.2.23:9000/chat_ws/`
        // 建立websocket连接
        this.websock = new WebSocket(wsuri, [token])
        // websocket接收信息
        this.websock.onmessage = this.websocketonmessage
        // 打开websocket
        this.websock.onopen = this.websocketonopen
        // websocket连接错误时重连
        this.websock.onerror = this.websocketonerror
      },
      websocketonopen() {
        window.console.log('连接成功')
      },
      websocketonerror() {
        //连接建立失败重连
        this.initWebSocket()
      },
      websocketonmessage(e) {
        //数据接收，首先要解析服务器传过来的数据
        const redata = JSON.parse(e.data)
        if (redata.msg_type==3) {
          // msg_type字段为3时，代表服务器给我发了文本信息了，注意是明确文本信息了
          // 例如对方发送 “你好” 给我时，msg_type就为3,text:'你好'
          // 下面这个if判断条件
          // this.dialogInfo.other_userid的意思是我跟这个人的对话框的ID
          // 比如我跟小明正在聊天，那我跟小明的对话框ID就假设为1
          // 此时我收到websocket服务器发来的文本信息text：在吗？，sender：1
          // 此时就意味着是小明给我发的信息，如果sender不是1，就代表着不是小明回我的
          if(this.dialogInfo.other_userid==redata.sender){
            // 如果跟我正在聊天的人给我回消息，下面这个代码，在此页面不影响
            // 这个传值的意思就是，将跟我聊天的对话框ID传递给其他组件或页面，可以用来判断未读信息条数，如果收到的信息的sender和我传递过去的ID相等，意味着未读信息就不需要加一
            this.$bus.$emit("hi",redata.sender);
          }
          // 当接收到数据时，就会更新消息列表，为防止没有对话框的用户不在信息列表，
          // 同时将该用户的ID记录下来，并记录已经更新过消息列表
          if(this.firstRunFlag==true){
            // 如果不是正在聊天的人给我回消息，就更新消息列表，为防止没有对话框的用户不在信息列表，
            if(this.dialogInfo.other_userid!=redata.sender){
              // getChatmessage()该函数为获取用户的列表，比如小明，小红等
              this.getChatmessage()
            }
            this.other_id=redata.sender
            this.firstRunFlag=false
          }
          // 当继续接受到数据时，由于已经记录过更新消息列表了，所以上一步不会执行
          // 当接收的数据如果和上次接收的数据发送ID相同时，也不会更新消息列表，因为该用户一定会有对话框在消息列表
          // 当接收的数据如果和上次接收的数据发送ID不相同时，即另外一个用户给我发消息时，
          // 又要更新消息列表，同样是防止没有对话框的用户不在信息列表
          if(this.other_id!=redata.sender){
            if(this.dialogInfo.other_userid!=redata.sender){
              this.getChatmessage()
            }
            this.firstRunFlag=true
          }
          //聊天框的人给你发消息时
          if(this.dialogInfo.other_userid==redata.sender){
            // userInfoList为信息列表
            this.userInfoList.push({
              url: this.urlhh, // url为用户的头像，
              info: redata.text, // 返回的文本信息
              timer: this.dealDate(), // 收到信息的时间
              position: "left", // 是对方给我发送信息，所以该信息应该是展示在左边
            });
          }
          // 这个for循环的意思是，遍历整个用户列表，找到发送的人的对话列表，然后将最近的信息和时间进行更新
          for(let i=0;i<this.userListData.length;i++){
            if(this.userListData[i].other_userid==redata.sender){
              this.userListData[i].last_message.text=redata.text,
              this.userListData[i].last_message.created=this.dealDate(new Date())
              break
            } 
          }
          // 收到信息就把信息列表的滚动条置底
          this.$nextTick(() => { // 一定要用nextTick
            this.setPageScrollTo();
            //页面滚动条距离顶部高度等于这个盒子的高度
            this.$refs.scrollBox.scrollTop = this.$refs.scrollBox.scrollHeight;
          })
        } else if (redata.msg_type==2) {
            window.console.log('下线')
        } else if (redata.msg_type==1) {
            window.console.log('上线')
        }else if (redata.msg_type==9) {
            // unread_count为未读消息个数，msg_type为9，返回未读信息个数
          if(this.dialogInfo.other_userid==redata.sender&&redata.unread_count!=0){
                // 如果我正在跟小明聊天，他又给我发个信息，我这个方法不能自动已读，只能手动发送信息，来告诉服务器我已读了
						let actions = {msg_type:6,user_pk:this.dialogInfo.other_userid,random_id:-5,dialog_id:this.dialogInfo.id}
						this.websocketsend(JSON.stringify(actions))
						// 上述就是手动发送已读，msg_type为6向服务器发送已读信息
						// for循环遍历用户列表，如果发送者的ID是和正在跟我聊天人的ID相等，就强制将用户列表上的跟我聊天的未读信息为0
						for(let i=0;i<this.userListData.length;i++){
							if(this.userListData[i].other_userid==redata.sender){
								// this.userListData[i].unread_count=0
								let user = this.userListData[i]
								user.unread_count=0
								this.$set(this.userListData, i, user);
								break
							} 
						}
					}
          for(let i=0;i<this.userListData.length;i++){
            if(this.userListData[i].other_userid==redata.sender){
              if(this.userListData[i].other_userid==this.dialogInfo.other_userid){
								// for循环遍历用户列表，如果发送者的ID是和正在跟我聊天人的ID相等，就强制将用户列表上的跟我聊天的未读信息为0
                // this.userListData[i].unread_count=0
                let user = this.userListData[i]
                user.unread_count=0
                this.$set(this.userListData, i, user);
              }else{
								// 如果发送者的ID和正在跟我聊天人的ID不相等，将用户列表上的那个人的未读信息重新渲染成最新的
                this.userListData[i].unread_count=redata.unread_count
                break
              }
            } 
          }
        }
      },
      websocketsend(Data) {
        //数据发送
        this.websock.send(Data)
      },
      websocketclose() {
        //关闭
      },
      //获取用户自己的信息
      getSelf() {
				//getUserDetail接口为自己写的获取自己的用户信息的接口，如头像，昵称，ID等
        getUserDetail().then((response) => {
          this.selfListData = response.data
        }).catch(function () {
        });
      },
      load(){
        this.page1++
				//获取下一页聊天列表
        this.getChatnextmessage()
      },
			// 滚动条置底时触发
      scrollEvent (e) {
        if (e.srcElement.scrollTop + e.srcElement.clientHeight + 1 > e.srcElement.scrollHeight) {
					//当isUpdate为true时，表示用户列表信息还存在，就要继续获取下一页，当isUpdate为false时，用户信息列表没有更多了
          if(this.isUpdate) {
            this.load();
          } else {
              this.$message("消息列表已加载完毕");
          }
        }
      },
      //获取下一页列表聊天数据
      getChatnextmessage() {
        return new Promise(resolve=>{
					// chatexport为自己写的获取用户信息列表的接口，我这里是一次传20条数据
        chatexport({
          page:this.page1
        }).then((response)=> {
          if(response.data.results.length<20){
						// 如果返回的信息列表条数小于20，就代表着不会有更多的信息了
            this.isUpdate=false
          }
          let userListDatanext = response.data.results
          userListDatanext.forEach(item=>{
            if(item.other_userimage==null){
              item.other_userimage='这里放上匿名用户的头像'
            }
						// 处理时间的格式
            item.last_message.created = this.dealDate(item.last_message.created)
          })
					// 将获取的下一页数据合并到用户列表数组中
          this.userListData = this.userListData.concat(userListDatanext);
          resolve()
        }).catch(function (error) {
            window.console.log(error);
            resolve()
        });
      })
      },
      //获取全部渲染到列表聊天数据
      getChatmessage() {
        return new Promise(resolve=>{
					// 滚动条置顶
          this.$nextTick(() => {
            let scrollEl = this.$refs.mianscroll;
            scrollEl.scrollTo({ top: 0, behavior: 'smooth' });
          });
          this.isUpdate=true
          this.page1=1
					//原理和上个函数类似
          chatexport({
            page:this.page1
          }).then((response)=> {
            if(response.data.results.length<20){
              this.isUpdate=false
            }
            this.userListData = response.data.results
            this.userListData.forEach(item=>{
                if(item.other_userimage==null){
                  item.other_userimage='这里放上匿名用户的头像'
                }
                item.last_message.created = this.dealDate(item.last_message.created)
              })
              resolve()
          }).catch(function (error) {
              window.console.log(error);
              resolve()
          });
        })
      },
      //获取个人聊天数据
      getPriChatmessage() {
        return new Promise((resolve)=>{
					//chatPriMessage为自己写的获取自己和别人的聊天记录，一次传20条数据
        chatPriMessage({
          dialog_with_id:this.act,//传值dialog_with_id为聊天对象的ID，我这里就是传对话框的ID，其实就是唯一识别就行
          page:this.page
        }).then((response)=> {
          if(response.data.results.length==0){
						//比如有40条聊天数据，获取第三页就为0了，就不能在继续获取了
            this.abcd=1
						//abcd为标识，为1时，不能再继续获取聊天数据了
            resolve()
						// 长度为0时，没数据了就return
            return
          }
          response.data.results.forEach(item=>{
						//is_out为true时为我发的信息，放右边
            if(item.is_out){
							//username字段可有可无（全文都是）
              this.userInfoList.unshift({
                url: this.selfListData.wechat_headimgurl,
                username: this.selfListData.name,
                info: item.text,
                timer: this.dealDate(item.created),//created字段为时间
                position: "right",
              });
              resolve()
            }else{
							//is_out为false时为聊天对象发的信息，放左边
              if(item.recipient_url){
                this.urlhh=item.recipient_url
              }else{
                this.urlhh='这里放匿名图片链接'
              }
							this.userInfoList.unshift({
							  url: this.urlhh,
							  username: item.recipient_username,
							  info: item.text,
							  timer: this.dealDate(item.created),
							  position: "left",
							});
              resolve()
            }
          })  
        }).catch(function (error) {
            window.console.log(error);
        });
      })
      },
      //获取个人最近感兴趣聊天数据（可有可无）
      getRecentmessage() {
        return new Promise((resolve)=>{
					// 这个接口可有可无
          getRecentgoods({
          dialog_with_id:this.act
        }).then((response)=> { 
          if(response.data.results.length){
            this.recenttext=response.data.results[0].text
            this.recenttext=this.recenttext.substr(0,50)
            this.goodsID=response.data.results[0].object_id
            this.category=response.data.results[0].category
          }else{
            this.recenttext=''
          }
          resolve()  
        }).catch(function (error) {
            window.console.log(error);
        });
      })
      },
			//此功能可有可无
      toDetail(){
        if(this.category==1){
          window.open('要去的链接', "_blank");
        }else if(this.category==2){
          window.open('要去的链接', "_blank");
        }else if(this.category==3){
          window.open('要去的链接', "_blank");
        }
      },
      //点击用户
      async getAct(val, index) {
        this.dialogInfo = val //点击用户列表上的详细信息
        this.page=1  
        this.isshow = 1   //更改样式
        this.index=index
        this.act=val.other_userid
        this.getRecentmessage() //可有可无
        this.$bus.$emit("hello", this.userListData[index].unread_count);//传值给其他组件
        this.userListData[index].unread_count=0		//未读改为0
        let actions = {msg_type:6,user_pk:val.other_userid,random_id:-7,dialog_id:val.id}
        this.websocketsend(JSON.stringify(actions))//发送已读信息
        // 点击用户切换数据时先清除监听滚动事件，防止出现没有历史数据的用户，滚动条为0，会触发滚动事件
        this.$refs.scrollBox.removeEventListener("scroll", this.srTop);
        //点击变色
        this.userInfoList = [];
        await this.getPriChatmessage()
				//滚动条置底
        this.$nextTick(() => { 
          this.setPageScrollTo();
          this.$refs.scrollBox.scrollTop = this.$refs.scrollBox.scrollHeight;
        })
      },
      //发送
      setUp() {
        if(this.textarea == "") {
          alert("发送信息不能为空!");
          return;
        }
        let actions = {text:this.textarea,msg_type:3,user_pk:this.act,random_id:-7}
        this.websocketsend(JSON.stringify(actions)) //发送至服务器
        this.userInfoList.push({
          url: this.selfListData.wechat_headimgurl,
          username: "超人",
          info: this.textarea,
          timer: this.dealDate(),
          position: "right",
        });//渲染到信息列表
        this.dialogInfo.last_message.text=this.textarea,//更新用户列表最近信息
        this.dialogInfo.last_message.created=this.dealDate(new Date()), //更新用户列表最近时间
        this.textarea = "";
        // 页面滚动到底部
        this.$nextTick(() => { // 一定要用nextTick
          this.setPageScrollTo();
          //页面滚动条距离顶部高度等于这个盒子的高度
          this.$refs.scrollBox.scrollTop = this.$refs.scrollBox.scrollHeight;
        })
      },
      // 监听键盘回车阻止换行并发送
      handlePushKeyword(event) {
        if (event.keyCode === 13) {
          event.preventDefault(); // 阻止浏览器默认换行操作
          this.setUp(); //发送文本
          return false;
        }
      },
      // 监听按的是ctrl + 回车，就换行
      lineFeed() {
        this.textarea = this.textarea + "\n";
      },
      //点击icon
      extend(val) {
        alert("你点击了：" + val);
      },
      //滚动条默认滚动到最底部
      setPageScrollTo() {
        //获取中间内容盒子的可见区域高度
        this.scrollTop = document.querySelector("#box").offsetHeight;
        setTimeout(() => {
          //加个定时器，防止上面高度没获取到，再获取一遍。
          if (this.scrollTop != this.$refs.scrollBox.offsetHeight) {
            this.scrollTop = document.querySelector("#box").offsetHeight;
          }
        }, 100);
        //scrollTop：滚动条距离顶部的距离。
        //把上面获取到的高度座位距离，把滚动条顶到最底部
        this.$refs.scrollBox.scrollTop = this.scrollTop;
        //判断是否有滚动条,有滚动条就创建一个监听滚动事件，滚动到顶部触发srTop方法
        this.$refs.scrollBox.addEventListener("scroll", this.srTop);
      },
      //滚动条到达顶部
      srTop() {
        //判断：当滚动条距离顶部为0时代表滚动到顶部了
        if (this.$refs.scrollBox.scrollTop == 0 && this.abcd == 0) {
          this.page = this.page + 1
					//获取下一页聊天数据
          this.getPriChatmessage()
        }
      },
			//处理时间函数
      dealDate(time) {
        let d = time ? new Date(time) : new Date();
        let year = d.getFullYear();
        let month = d.getMonth() + 1;
        let day = d.getDate();
        let hours = d.getHours();
        let min = d.getMinutes();
        let seconds = d.getSeconds();
        if (month < 10) month = '0' + month;
        if (day < 10) day = '0' + day;
        if (hours < 0) hours = '0' + hours;
        if (min < 10) min = '0' + min;
        if (seconds < 10) seconds = '0' + seconds;
  
        return (year + '/' + month + '/' + day + ' ' + hours + ':' + min);
      }
    },
  };
  </script>